package com.bugsnag.ohos;

import ohos.aafwk.content.Intent;
import ohos.aafwk.content.IntentParams;
import ohos.event.commonevent.CommonEventData;
import ohos.event.commonevent.CommonEventSubscribeInfo;
import ohos.event.commonevent.CommonEventSubscriber;
import ohos.event.commonevent.MatchingSkills;

import com.bugsnag.ohos.internal.ImmutableConfig;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * SystemBroadcastReceiver
 *
 * @since 2021-07-01
 */
public class SystemBroadcastReceiver {
    private static final String INTENT_ACTION_KEY = "Intent Action";
    private Client client;
    private Logger logger;
    private SystemCommonEventSubscriber systemCommonEventSubscriber;
    private Map<String, BreadcrumbType> actions;

    /**
     * constructor
     *
     * @param client
     * @param logger
     */
    public SystemBroadcastReceiver(Client client, Logger logger) {
        this.client = client;
        this.logger = logger;
        actions = buildActions();
    }

    /**
     * constructor
     *
     * @param receiver
     * @param log
     */
    public void register(SystemBroadcastReceiver receiver, Logger log) {
        if (!receiver.actions.isEmpty()) {
            MatchingSkills matchingSkills = new MatchingSkills();
            Set<String> keys = receiver.actions.keySet();
            for (String key : keys) {
                matchingSkills.addEvent(key);
            }
            systemCommonEventSubscriber = new SystemCommonEventSubscriber(new CommonEventSubscribeInfo(matchingSkills));
            ContextExtensions.registerReceiverSafe(systemCommonEventSubscriber, log);
        }
    }

    /**
     * unregister subscriber
     */
    public void unregister() {
        ContextExtensions.unregisterReceiverSafe(systemCommonEventSubscriber, logger);
    }

    /**
     * isOhosKey
     *
     * @param actionName
     * @return boolean
     */
    public boolean isOhosKey(String actionName) {
        return actionName.startsWith("ohos.");
    }

    /**
     * shortenActionNameIfNeeded
     *
     * @param action
     * @return action name
     */
    public String shortenActionNameIfNeeded(String action) {
        if (isOhosKey(action)) {
            return action.substring(action.lastIndexOf("."));
        }
        return action;
    }

    /**
     * SystemCommonEventSubscriber
     *
     * @since 2021-07-27
     */
    private class SystemCommonEventSubscriber extends CommonEventSubscriber {
        SystemCommonEventSubscriber(CommonEventSubscribeInfo subscribeInfo) {
            super(subscribeInfo);
        }

        @Override
        public void onReceiveEvent(CommonEventData commonEventData) {
            Map<String, Object> meta = new HashMap();
            Intent intent = commonEventData.getIntent();
            String fullAction = intent.getAction();
            if (TextUtils.isEmpty(fullAction)) {
                return;
            }
            String shortAction = shortenActionNameIfNeeded(fullAction);
            meta.put(INTENT_ACTION_KEY, fullAction);
            addExtrasToMetadata(intent, meta, shortAction);

            BreadcrumbType type;
            if (actions.get(fullAction) != null) {
                type = actions.get(fullAction);
            } else {
                type = BreadcrumbType.STATE;
            }
            client.leaveBreadcrumb(shortAction, meta, type);
        }
    }

    private void addExtrasToMetadata(Intent intent, Map<String, Object> meta, String shortAction) {
        IntentParams extras = intent.getParams();
        if (extras != null) {
            Set<String> set = extras.keySet();
            if (set != null) {
                for (String key : set) {
                    Object valObj = extras.getParam(key);
                    if (valObj == null) {
                        continue;
                    }
                    String strVal = valObj.toString();
                    if (isOhosKey(key)) { // shorten the Intent action
                        meta.put("Extra", shortAction + ": " + strVal);
                    } else {
                        meta.put(key, strVal);
                    }
                }
            }
        }
    }

    /**
     * Builds a map of intent actions and their breadcrumb type (if enabled).
     * <p>
     * Noisy breadcrumbs are omitted, along with anything that involves a state change.
     *
     * @return the action map
     */
    private Map<String, BreadcrumbType> buildActions() {
        Map<String, BreadcrumbType> breadcrumbTypeMap = new HashMap();
        ImmutableConfig config = client.getConfig();

        if (!config.shouldDiscardBreadcrumb(BreadcrumbType.USER)) {
            breadcrumbTypeMap.put("usual.event.DISCHARGING", BreadcrumbType.USER);
            breadcrumbTypeMap.put("usual.event.CHARGING", BreadcrumbType.USER);
            breadcrumbTypeMap.put("usual.event.CLOSE_SYSTEM_DIALOGS", BreadcrumbType.USER);
            breadcrumbTypeMap.put("usual.event.CONFIGURATION_CHANGED", BreadcrumbType.USER);
        }
        if (!config.shouldDiscardBreadcrumb(BreadcrumbType.STATE)) {
            breadcrumbTypeMap.put("usual.event.POWER_CONNECTED", BreadcrumbType.STATE);
            breadcrumbTypeMap.put("usual.event.POWER_DISCONNECTED", BreadcrumbType.STATE);
            breadcrumbTypeMap.put("usual.event.AIRPLANE_MODE", BreadcrumbType.STATE);
            breadcrumbTypeMap.put("usual.event.BATTERY_LOW", BreadcrumbType.STATE);
            breadcrumbTypeMap.put("usual.event.BATTERY_OKAY", BreadcrumbType.STATE);
            breadcrumbTypeMap.put("usual.event.BOOT_COMPLETED", BreadcrumbType.STATE);
            breadcrumbTypeMap.put("usual.event.CONFIGURATION_CHANGED", BreadcrumbType.STATE);
            breadcrumbTypeMap.put("usual.event.DATE_CHANGED", BreadcrumbType.STATE);
            breadcrumbTypeMap.put("usual.event.LOCALE_CHANGED", BreadcrumbType.STATE);
            breadcrumbTypeMap.put("usual.event.SCREEN_OFF", BreadcrumbType.STATE);
            breadcrumbTypeMap.put("usual.event.SCREEN_ON", BreadcrumbType.STATE);
            breadcrumbTypeMap.put("usual.event.TIMEZONE_CHANGED", BreadcrumbType.STATE);
            breadcrumbTypeMap.put("usual.event.TIME_TICK", BreadcrumbType.STATE);
            breadcrumbTypeMap.put("usual.event.DEVICE_IDLE_MODE_CHANGED", BreadcrumbType.STATE);
            breadcrumbTypeMap.put("usual.event.POWER_SAVE_MODE_CHANGED", BreadcrumbType.STATE);
        }
        if (!config.shouldDiscardBreadcrumb(BreadcrumbType.NAVIGATION)) {
            breadcrumbTypeMap.put("common.event.IVI_SLEEP", BreadcrumbType.NAVIGATION);
            breadcrumbTypeMap.put("common.event.IVI_STANDBY", BreadcrumbType.NAVIGATION);
        }
        return breadcrumbTypeMap;
    }
}
